package rw.main;


import rw.gameobject.ExampleGameObject;
import rw.input.Input;
import rw.input.SynchronizedSign;
import rw.rwbehaviour.RwBehaviour;

import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author RWdaze
 */
public class Main {
    /**
     * 整个游戏场景之中的所有游戏对象列表
     */
    private static final LinkedList<RwBehaviour> GameObjects = new LinkedList<>();

    /**
     * 下一帧即将会加入游戏场景的对象列表
     */
    private static final LinkedList<RwBehaviour> addGameObjects = new LinkedList<>();

    /**
     * 下一帧即将会删除游戏场景的对象列表
     */
    private static final LinkedList<RwBehaviour> remGameObjects = new LinkedList<>();

    /**
     * 为了和画板刷新同步，从而使两个线程以阻塞的形式同步
     */
    public static BlockingQueue<Object> bq = new ArrayBlockingQueue<>(1);

    /**
     * 需要向游戏场景中添加的游戏对象
     *
     * @param gameObject 需要添加的游戏对象
     */
    public static void addGameObject(RwBehaviour gameObject) {
        addGameObjects.add(gameObject);
    }

    /**
     * 需要向游戏场景中删除的游戏对象
     *
     * @param gameObject 需要删除的游戏对象
     */
    public static void remGameObject(RwBehaviour gameObject) {
        remGameObjects.add(gameObject);
    }

    /**
     * 获得场景中的所有游戏对象
     * 注意！请尽量不要在获得的列表中增加或删除游戏对象。
     * 如果想要增加或者删除相应的游戏对象请使用addGameObject和remGameObject函数
     * 它们会安全的在每一帧的结束时统一增加或者删除。
     * <p>
     * 如果直接操作列表，则有可能产生未知的错误
     *
     * @return 游戏对象列表
     */
    public static LinkedList<RwBehaviour> getGameObjects() {
        return GameObjects;
    }

    /**
     * 游戏窗口的宽
     */
    public static final int WIDTH = 816;

    /**
     * 游戏窗口的高
     */
    public static final int HEIGHT = 639;

    /**
     * 游戏的标题
     */
    private static final String TITLE = "RWGameEngine";

    /**
     * 游戏小图标的图片（放在资源文件夹pic内
     */
    private static final String IMAGE = "star.png";

    /**
     * 相关的按键操作。实际上，修改这里不会改变真正的按键位置。
     * 所以请不要改变这里的值
     */
    public static final String UP = "Up";

    public static final String DOWN = "Down";

    public static final String LEFT = "Left";

    public static final String RIGHT = "Right";

    public static final String A = "A";

    public static final String B = "B";

    public static final String C = "C";

    public static final String SPACE = "Space";

    public static final String SHIFT = "Shift";

    public static void main(String[] args) {
        // 向游戏场景之中加入游戏对象
        GameObjects.add(new ExampleGameObject());

        // 获取帧数同步对象和输入采集对象
        SynchronizedSign us = SynchronizedSign.getInstance();
        Input in = Input.getInstance();

        // 输入采集进行初始化，添加入相应的按键
        in.putKey(UP, KeyEvent.VK_UP, KeyEvent.VK_W);
        in.putKey(DOWN, KeyEvent.VK_DOWN, KeyEvent.VK_S);
        in.putKey(LEFT, KeyEvent.VK_LEFT, KeyEvent.VK_A);
        in.putKey(RIGHT, KeyEvent.VK_RIGHT, KeyEvent.VK_D);
        in.putKey(A, KeyEvent.VK_Z, KeyEvent.VK_ENTER);
        in.putKey(B, KeyEvent.VK_X);
        in.putKey(C, KeyEvent.VK_ESCAPE);
        in.putKey(SPACE, KeyEvent.VK_SPACE);
        in.putKey(SHIFT, KeyEvent.VK_SHIFT);

        // 把游戏场景中的所有游戏物体执行start函数
        start();

        // 新建游戏窗口
        StartFrame sj = new StartFrame(HEIGHT, WIDTH, TITLE, IMAGE);

        // 在帧数同步对象中，加入它该执行的函数
        // 1、给输入采集对象发出信号
        us.acts.add(in::synchronizedSign);
        // 2、给所有游戏对象的update发出信号
        us.acts.add(Main::update);
        // 3、刷新画板
        us.acts.add(() ->
        {
            sj.paint();

            //进行阻塞，等到画板刷新完成的时候，再往下执行
            try {
                bq.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        us.start();
    }

    /**
     * 每一帧的刷新函数
     */
    public static void update() {
        // 遍历所有的游戏对象，并且执行它们相应的update函数
        for (RwBehaviour rwBehaviour : GameObjects) {
            if (rwBehaviour.active) {
                rwBehaviour.update();
            }
        }
        // 遍历所有需要加入游戏场景中的游戏对象，并且执行它们相应的start函数
        for (RwBehaviour rwBehaviour : addGameObjects) {
            rwBehaviour.start();
        }

        // 游戏场景中根据删除添加列表，该删除的删除，该添加的进行添加，并且清空删除添加列表。
        GameObjects.addAll(addGameObjects);
        GameObjects.removeAll(remGameObjects);
        remGameObjects.clear();
        addGameObjects.clear();
    }

    /**
     * 场景加载时，给所有游戏对象执行开始函数
     */
    public static void start() {
        for (RwBehaviour rwBehaviour : GameObjects) {
            if (rwBehaviour.active) {
                rwBehaviour.start();
            }
        }
    }
}